package com.gukun.springboot.tdengine.service.delete;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gukun.springboot.tdengine.dao.DeleteTaskMapper;
import com.gukun.springboot.tdengine.dao.TDEngineDao;
import com.gukun.springboot.tdengine.domain.delete.DeleteLog;
import com.gukun.springboot.tdengine.domain.delete.DeleteTask;
import com.gukun.springboot.tdengine.domain.exception.util.ServiceExceptionUtil;
import com.gukun.springboot.tdengine.enums.DataDeleteType;
import com.gukun.springboot.tdengine.service.TDEngineService;
import com.gukun.springboot.tdengine.service.backuprecover.entity.Table;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.thirdparty.com.google.common.util.concurrent.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

/**
 * @author: 4998
 * @createDate: 2025-06-04  09:42
 * @description:
 */
@Service
@Slf4j
public class DeleteTaskService {
    @Autowired
    private DeleteTaskMapper deleteTaskMapper;
    @Autowired
    private TDEngineService tdEngineService;
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    private DeleteLogService deleteLogService;

    private static final ConcurrentHashMap<String, ScheduledFuture<?>> RUNNING_TASKS = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String,String> RUNNING_TASK_LOG = new ConcurrentHashMap<>();

    /**
     * 初始化默认任务，默认任务默认为每月最后一天执行，默认保存时间2年
     *
     * @return
     */
    public boolean initDefaultTask(DeleteTask deleteTask){
        LambdaQueryWrapper<DeleteTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeleteTask::getDbName,  deleteTask.getDbName());
        queryWrapper.eq(DeleteTask::getDefaultTask, 1);
        long num = deleteTaskMapper.selectCount(queryWrapper);
        if(num == 0){
            deleteTask.setName("默认任务");
            deleteTask.setStatus(0);
            deleteTask.setTaskPriority(100000);
            deleteTask.setPeriod(DataDeleteType.TWO_YEAR.name());
            //每月最后一天 00:00:00 执行
            deleteTask.setCron("0 0 0 L * ?");
            deleteTask.setDefaultTask(1);
            deleteTask.setTaskDesc("");
            deleteTask.setCreateTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            return deleteTaskMapper.insert(deleteTask) == 1;
        }
        throw ServiceExceptionUtil.exception0(500,  "默认任务已存在");
    }

    public boolean deleteById(String id){
        if(StringUtils.isBlank(id)){
            throw ServiceExceptionUtil.exception0(500,  "id不能为空");
        }
        deleteLogService.deleteByTaskId(id);
        deleteTaskMapper.deleteById(id);
        return true;
    }

    /**
     * 执行删除数据的定时任务
     */
    public void executeTask(DeleteTask deleteTask) throws SQLException {
        if(deleteTask != null){
            long timestamp = DataDeleteType.getTimestamp(deleteTask.getPeriod());
            if(timestamp == 0){
                log.info("永久保存任务，不删除");
            }else{
                //获取数据库连接
                TDEngineDao tdEngineDao = tdEngineService.getTDEngineDao(deleteTask.getHost(), deleteTask.getPort(), deleteTask.getUsername(),  deleteTask.getPassword(), deleteTask.getDbName());
                List<String> tableNames = new ArrayList<>();
                //获取需要处理的所有的表格
                if(deleteTask.getDefaultTask() == 1){
                    //这说明是默认任务，需要去全部表格
                    tableNames = tdEngineService.showTables(deleteTask.getHost(), deleteTask.getPort(), deleteTask.getUsername(),  deleteTask.getPassword(), deleteTask.getDbName(),"");
                }else{
                    //指定表格
                    if(StringUtils.isNotBlank(deleteTask.getTableNames())){
                        tableNames = Arrays.asList(deleteTask.getTableNames().split(","));
                    }
                }
                if(tableNames.isEmpty()){
                    return;
                }
                //获取所有优先级高于此任务的任务
                Set<String> highPriorityTaskTable = getSuperPriorityTaskTable(deleteTask);
                //将优先级高于此任务的表格从任务表格中剔除
                tableNames.removeAll(highPriorityTaskTable);
                RateLimiter rateLimiter = RateLimiter.create(3000);
                String dbName = deleteTask.getDbName();
                tdEngineDao.useDb(dbName);
                log.info("开始删除表格过期数据");
                for (String tableName : tableNames) {
                    if (rateLimiter.tryAcquire()) {
                        try {
                            //删除表格
                            tdEngineDao.deleteDataByPeriod(dbName, tableName, timestamp);
                        } catch (Exception e) {
                            log.error("删除表格失败", e);
                        }
                    }
                }
                log.info("删除表格过期数据完成");
            }
        }
    }

    /**
     * 获取优先级更高的任务表格
     */
    public Set<String> getSuperPriorityTaskTable(DeleteTask deleteTask){
        int taskPriority = deleteTask.getTaskPriority();
        String host = deleteTask.getHost();
        int port = deleteTask.getPort();
        String dbName = deleteTask.getDbName();
        LambdaQueryWrapper<DeleteTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeleteTask::getHost, host)
                .eq(DeleteTask::getPort, port)
                .eq(DeleteTask::getDbName, dbName);
        queryWrapper.lt(DeleteTask::getTaskPriority,taskPriority);
        List<DeleteTask> all = deleteTaskMapper.selectList(queryWrapper);
        Set<String> tableNames = new HashSet<>();
        all.forEach(deleteTaskTemp -> {
            if(deleteTaskTemp.getTableNames() != null){
                tableNames.addAll(Arrays.asList(deleteTaskTemp.getTableNames().split(",")));
            }
        });
        return tableNames;
    }

    /**
     * 服务启动时启动定时任务
     */
    public void initTask() {
        LambdaQueryWrapper<DeleteTask> queryWrapper = new LambdaQueryWrapper<>();
        //获取已经启用的任务
        queryWrapper.eq(DeleteTask::getStatus,1);
        for (DeleteTask deleteTask : deleteTaskMapper.selectList(queryWrapper)) {
            registerTask(deleteTask);
        }
    }

    public static void saveFile(MultipartFile multipartFile, String filePath) throws IOException {
        Path path = Paths.get(filePath);
        // 确保父目录存在
        Files.createDirectories(path.getParent());
        // 使用try-with-resources确保流关闭
        try (InputStream inputStream = multipartFile.getInputStream()) {
            Files.copy(inputStream, path);
        }
    }

    /**
     * 解析文件中的测点名称
     */
    public List<String> analyzeFile(MultipartFile multipartFile) throws IOException {
        String folderDir = System.getProperty("user.dir") + File.separator + UUID.randomUUID();
        String filePath = folderDir + File.separator + multipartFile.getOriginalFilename();
        saveFile(multipartFile, filePath);
        File file = new File(filePath);
        List<String> dataList = new ArrayList<>();
        ExcelTypeEnum fileType = null;
        if(file.getName().endsWith(".xlsx")){
            fileType = ExcelTypeEnum.XLSX;
        }else if(file.getName().endsWith(".csv")){
            fileType = ExcelTypeEnum.CSV;
        }else{
            fileType = ExcelTypeEnum.XLS;
        }
        try{
            dataList = readXlsxFile(file,fileType);
            File folder = new File(folderDir);
            FileUtils.deleteDirectory(folder);
        }catch (Exception e){
            throw ServiceExceptionUtil.exception0(500,"解析文件失败:"+e.getMessage());
        }
        return dataList;
    }

    public List<String> readXlsxFile(File file,ExcelTypeEnum fileType){
        List<String> dataList = new ArrayList<>();
        EasyExcel.read(file, Table.class, new ReadListener<Table>() {
            @Override
            public void invoke(Table o, AnalysisContext analysisContext) {
                dataList.add(o.getTableName());
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("读取完成:"+dataList.size());
            }
        }).excelType(fileType).sheet().doRead();
        return dataList;
    }
    /**
     * 获取任务列表
     */
    public List<DeleteTask> list(DeleteTask deleteTask) {
        LambdaQueryWrapper<DeleteTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeleteTask::getHost,deleteTask.getHost());
        queryWrapper.eq(DeleteTask::getPort,deleteTask.getPort());
        queryWrapper.orderByDesc(DeleteTask::getCreateTime);
        //返回所有任务
        return deleteTaskMapper.selectList(queryWrapper);
    }

    public Boolean saveOrUpdate(DeleteTask deleteTask) throws IOException {
        if(deleteTask.getMultipartFile() != null){
            deleteTask.setTableNames(String.join(",", analyzeFile(deleteTask.getMultipartFile())));
        }
        deleteTask.setStatus(0);
        if(deleteTask.getId() == null){
            deleteTask.setDefaultTask(0);
        }
        if(StringUtils.isBlank(deleteTask.getId())){
            deleteTask.setCreateTime(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            deleteTaskMapper.insert(deleteTask);
        }else{
            deleteTask.setUpdateTime(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            deleteTaskMapper.updateById(deleteTask);
        }
        return true;
    }

    public void registerTask(DeleteTask deleteTask) {
        ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(() -> {
            DeleteLog deleteLog = null;
            try {
                deleteLog = new DeleteLog();
                deleteLog.setTaskId(deleteTask.getId());
                deleteLog.setStartTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                deleteLog.setPeriod(deleteTask.getPeriod());
                deleteLog.setStatus(1);
                deleteLogService.saveOrUpdate(deleteLog);
                RUNNING_TASK_LOG.put(deleteTask.getId(), deleteLog.getId());
                executeTask(deleteTask);
                deleteLog.setEndTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                deleteLog.setTaskLog("删除表格过期数据成功");
                deleteLog.setStatus(0);
                deleteLogService.saveOrUpdate(deleteLog);
                RUNNING_TASKS.remove(deleteTask.getId());
                RUNNING_TASK_LOG.remove(deleteTask.getId());
            } catch (Exception e) {
                if(deleteLog == null){
                    deleteLog = new DeleteLog();
                    deleteLog.setTaskId(deleteTask.getId());
                    deleteLog.setStartTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                }
                deleteLog.setEndTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                deleteLog.setTaskLog("删除表格失败："+e.getMessage());
                deleteLog.setStatus(0);
                deleteLogService.saveOrUpdate(deleteLog);
                RUNNING_TASKS.remove(deleteTask.getId());
                RUNNING_TASK_LOG.remove(deleteTask.getId());
                throw new RuntimeException(e);
            }
        }, triggerContext -> {
            CronTrigger cronTrigger = new CronTrigger(deleteTask.getCron());
            return cronTrigger.nextExecution(triggerContext);
        });
        if(Objects.nonNull(scheduledFuture)){
            RUNNING_TASKS.put(deleteTask.getId(), scheduledFuture);
            deleteTask.setStatus(1);
            deleteTaskMapper.updateById(deleteTask);
            log.info("任务已启动:"+deleteTask.getId());
        }
    }

    public Boolean start(String id) {
        LambdaQueryWrapper<DeleteTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeleteTask::getId,id);
        DeleteTask deleteTask = deleteTaskMapper.selectOne(queryWrapper);
        if(deleteTask == null){
            return false;
        }
        registerTask(deleteTask);
        return true;
    }

    public Boolean stop(String id) {
        ScheduledFuture<?> scheduledFuture = RUNNING_TASKS.get(id);
        if(Objects.nonNull(scheduledFuture)){
            //查看是否有任务正在执行，有的话就停止
            scheduledFuture.cancel(true);
            RUNNING_TASKS.remove(id);
            if(RUNNING_TASK_LOG.contains(id)){
                String logId = RUNNING_TASK_LOG.get(id);
                DeleteLog deleteLog = deleteLogService.getById(logId);
                deleteLog.setTaskLog("任务手动停止！");
                deleteLog.setEndTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
                deleteLog.setStatus(0);
                deleteLogService.saveOrUpdate(deleteLog);
            }
        }
        DeleteTask  deleteTask = deleteTaskMapper.selectById(id);
        deleteTask.setStatus(0);
        deleteTaskMapper.updateById(deleteTask);
        log.info("任务已停止:"+id);
        return true;
    }
}
